package com.mach.platform.sprider.opc;

import com.mach.platform.sprider.getter.GeneralDev;
import com.mach.platform.sprider.getter.MainWork;
import com.mach.platform.sprider.getter.DataLogService;
import com.mach.platform.util.SqlHelper;
import com.mach.platform.util.U;
import lombok.extern.slf4j.Slf4j;
import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.SyncAccess;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Slf4j
public class OPCDADev implements GeneralDev {

    public static final int PERIOD = 1000 * 60*1;

    public static final int ACCESS_SLEEP = PERIOD + 1;

    protected  Map<String, Object> devInfoMap = null;
    private  SqlHelper sqlHelper = null;
    private  DataLogService dataLogService = null;
    private String commAddr = null;
    private String ip = null;
    private Integer devId = null;
    private String userName = null;
    private String passwd = null;
    private String progid = null;
    private String domain = null;
    private SyncAccess access = null;
    private boolean isRun = false;

    protected OPCDADev(Map<String, Object> devInfoMap, SqlHelper sqlHelper, DataLogService dataLogService) {

        this.devInfoMap = devInfoMap;

        this.sqlHelper = sqlHelper;

        this.dataLogService = dataLogService;

        this.init();

    }

    private void init() {

        this.commAddr = (String)this.devInfoMap.get("prol");

        this.devId = (Integer) this.devInfoMap.get("devId");

        initCommAddr(this);
    }

    public String getServerKey(){
        return OPCDAServer.opcServerKey(this.ip, this.progid);
    }

    private static  void initCommAddr(OPCDADev dev ) {
        if(null == dev.commAddr)return;

        String[] addrStrs = dev.commAddr.split(":");

        if(addrStrs.length < 6){
            return;
        }
//        OPCDA:192.168.32.129:OPCServer.WinCC::administrator:123-abc
        dev.ip = addrStrs[1];
        dev.progid = (addrStrs[2]);
        dev.domain = (addrStrs[3]);
        dev.userName = (addrStrs[4]);
        dev.passwd = (addrStrs[5]);

    }
    @Override
    public void start() {
        if(!this.isRun){
            U.cachedThreadPool.execute(this);
        }
    }

    @Override
    public void run() {

        if(isRun) {
            log.info("OPCDAServer dev("+this.devId+") is runNing return...");
            return;
        }

        this.isRun = true;

        OPCDAServer server = OPCDAServer.getOrNew(this);

        try {

            server.getRealServer().connect();

            this.access = new SyncAccess(server.getRealServer(), PERIOD);

            Map<Integer, Object> collMap = (Map<Integer, Object>) this.devInfoMap.get("coll");

            Set<Map.Entry<Integer, Object>> collEntrys = collMap.entrySet();

            for(Map.Entry<Integer, Object> collEntry : collEntrys){
                Map<String, Object> coll = (Map<String, Object>) collEntry.getValue();

                Integer devId = (Integer)this.devInfoMap.get("devId");
                String collName = (String)coll.get("collName");
                String collAddr = (String)coll.get("collAddrStr");
//                Integer collLen = (Integer)coll.get("collLen");
                String collUnit = (String)coll.get("collUnit");
                String collDataType = (String)coll.get("collDataType");
                String prol = (String)this.devInfoMap.get("prol");
//                Object result = null;

                this.access.addItem(collAddr, new DataCallback() {
                    @Override
                    public void changed(Item item, ItemState itemState) {
                        Object result = null;
                        try {
                            if("float".equals(collDataType)){
                                result = itemState.getValue().getObjectAsFloat();
                            }
                            if("float/10".equals(collDataType)){
                                result = itemState.getValue().getObjectAsFloat() /10.0f;
                            }
                            if("float/100".equals(collDataType)){
                                result = itemState.getValue().getObjectAsFloat() /100.0f;
                            }
                            if("float/1000".equals(collDataType)){
                                result = itemState.getValue().getObjectAsFloat() /1000.0f;
                            }
                            if("float/60".equals(collDataType)){
                                result = itemState.getValue().getObjectAsFloat() /60.0f;
                            }
                            if("int".equals(collDataType)){
                                result = itemState.getValue().getObjectAsInt();
                            }
                            if("long".equals(collDataType)){
                                result = itemState.getValue().getObjectAsLong();
                            }
                            if("short".equals(collDataType)){
                                result = itemState.getValue().getObjectAsShort();
                            }
                        } catch (JIException e) {
                            e.printStackTrace();
                        }

                        if(result != null){
                            try {
//                                sqlHelper.updateAsync(
//                                        "replace into iot_dev_cur_data_win" +
//                                                "(dev_id, data_type,dvalue,unit,uptime)" +
//                                                " value("+devId+", '"+collName+"', "+result+",'"+collUnit+"',now())");
//
//                                sqlHelper.updateAsync(
//                                        "insert into iot_dev_data_win" +
//                                                "(order_num,dev_id, the_time,data_type,dvalue)" +
//                                                " value(1,"+devId+",now(), '"+collName+"', "+result+")");

                                MainWork.addResult(devInfoMap, coll, result);

//                                OPCDADev.this.dataLogService.
//                                        addDataLogAsync(devId, new Date(), collName, result);

                            } catch (Exception e) {
                                e.printStackTrace();
                                System.err.println("error saveToDb... msg:" + e.getLocalizedMessage() + " devId=" + OPCDADev.this.devId + "");
                            }
                        }

                    }
                });

            }

            /** 开始监听 */
            access.bind();

            /** 当前线程休眠时间单位：毫秒 */
            Thread.sleep(ACCESS_SLEEP);
            /** 监听 结束 */
            access.unbind();


        } catch (Exception e) {
//            e.printStackTrace();
            log.info("OPCDAServer Connect... excep:" + e.getLocalizedMessage());
        }finally {
            server.dispose();
            this.isRun = false;
        }
    }

    public Map<String, Object> getDevInfoMap() {
        return devInfoMap;
    }

    public void setDevInfoMap(Map<String, Object> devInfoMap) {
        this.devInfoMap = devInfoMap;
        this.init();
    }

    public SqlHelper getSqlHelper() {
        return sqlHelper;
    }

    public void setSqlHelper(SqlHelper sqlHelper) {
        this.sqlHelper = sqlHelper;
    }

    public DataLogService getDataLogService() {
        return dataLogService;
    }

    public void setDataLogService(DataLogService dataLogService) {
        this.dataLogService = dataLogService;
    }

    public String getCommAddr() {
        return commAddr;
    }

    public void setCommAddr(String commAddr) {
        this.commAddr = commAddr;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getDevId() {
        return devId;
    }

    public void setDevId(Integer devId) {
        this.devId = devId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getProgid() {
        return progid;
    }

    public void setProgid(String progid) {
        this.progid = progid;
    }

    public String getDomain() {
        return domain;
    }

    public void setDomain(String domain) {
        this.domain = domain;
    }

    private  static  final HashMap<Integer, OPCDADev> devs = new HashMap<Integer, OPCDADev>();

    public static OPCDADev getOrNew(Map<String, Object> devInfoMap, SqlHelper sqlHelper, DataLogService dataLogService){
//        OPCDADev  devNew = new OPCDADev(devInfoMap, sqlHelper, dataLogService);

        Integer  devId = (Integer)devInfoMap.get("devId");
        if(devId == null) return null;

        OPCDADev dev = devs.get(devId);
        if(dev == null){
            dev = new OPCDADev(devInfoMap, sqlHelper, dataLogService);;
            devs.put(devId, dev);
        }
        dev.setDevInfoMap(devInfoMap);
        return dev;
    }
    @Override
    public void updateDevInfo(Map<String, Object> devInfo) {
        this.devInfoMap = devInfo;
    }

    @Override
    public Object getValueByColl(Map<String, Object> coll) throws IOException {
        return null;
    }

    @Override
    public Object getValueByCollName(String collName) throws IOException {
        return null;
    }

    @Override
    public Map<String, Object> getCollByName(String collName) {

        Map<Integer, Object> collMap = (Map<Integer, Object>) this.devInfoMap.get("coll");

        Set<Map.Entry<Integer, Object>> collEntrys = collMap.entrySet();

        Map<String, Object> coll = null;
        for(Map.Entry<Integer, Object> collEntry : collEntrys){
            Map<String, Object> collTmp = (Map<String, Object>) collEntry.getValue();


            String collNameFrObj = (String)collTmp.get("collName");

            if(collName.equals(collName)){
                coll = collTmp;
                break;
            }
        }
        return coll;
    }

    @Override
    public void cmd(Integer cmdId,String cmd, String param) {
        throw new RuntimeException("Un Support...");
    }
}
